#include "leaf_node.h"
#include "node_manager.h"
#include "leaf_register.h"
#include "level_register.h"

using namespace bstree;

LeafNode::LeafNode(unsigned int level,unsigned int offset,unsigned int size) : Node(level,offset,size){
}

LeafNode::~LeafNode(){
	for(Registers::iterator it = regs.begin(); it!=regs.end();++it){
		delete(*it);
	}
	regs.clear();
}

bool LeafNode::insert(const NodeRegister& reg ,LevelNode* root, NodeManager& manager){
	if(!Node::insert(reg))return false;	
	if( (this->getUsedSize()) >(this->getSize()-16)){


		//Veo que no sea root para que tenga hermanos
		if(root!=NULL){
			Register* keyReg=(dynamic_cast<LeafRegister*>(*(regs.begin())))->getKeyRegister();
			LevelRegister keyRegister(*keyReg,NodeManager::NO_OFFSET);
			delete keyReg;

			//como hay overflow busco si tengo hermano derecho en mismo nodo nivel
			if(root->isLast(keyRegister)){
				//Uso el izquierdo
				LeafNode* leftNode=NULL;
				leftNode = dynamic_cast<LeafNode*>(manager.readNode(this->getPreviousNode()));
				//Calculo el tamaño de los registros que tendria que mover para que no halla overflow
				reacomodateRegistersToLeft(root, leftNode,this, manager );
				delete leftNode;

			}
			else{
				//Uso el derecho
				LeafNode* rightNode=NULL;
				rightNode = dynamic_cast<LeafNode*>(manager.readNode(this->getNextNode()));
				//Calculo el tamaño de los registros que tendria que mover para que no halla overflow
				reacomodateRegistersToRight(root, this,rightNode, manager );
				delete rightNode;
			}
		}
		else{
			/* overflow */
			/* localizar el elemento del medio si el tamaño es fijo 
			sino este algoritmo es otro */
			Registers::iterator it = regs.begin();
			unsigned int registersSize=0;
			while(registersSize<this->getSize()/2){
				registersSize+=(*it)->getSize();
				it++;
			}

			Register* lR = dynamic_cast<LeafRegister*>(*it)->getKeyRegister();
			overflowRegister = new LevelRegister(*lR,NodeManager::NO_OFFSET);
			delete lR;
			//overflowRegister = dynamic_cast<LeafRegister*>(*it)->getKeyRegister();
			/* crear el nuevo nodo */		
			newNode = new LeafNode(this->level,NodeManager::NO_OFFSET,this->size);
	
			Registers::iterator it2 = it;		
			for(;it!=regs.end();++it){
				newNode->insert(*(*it));
				delete(*it);
			}
			regs.erase(it2,regs.end());
			this->foverflow = true;
			registerCount = regs.size();
		}

	}else{
		this->fmodified = true;
	}

	return true;
}

bool LeafNode::reacomodateRegistersToLeft(LevelNode* root, LeafNode* leftNode,LeafNode* centerNode, NodeManager& manager ){
	bool ret =false;

	Register* keyReg=(dynamic_cast<LeafRegister*>(*((centerNode->regs).begin())))->getKeyRegister();
	LevelRegister keyRegister(*keyReg,NodeManager::NO_OFFSET);
	std::pair<bool,unsigned int> lf = root->getSubTree(*keyReg);
	keyRegister.setRightChild(lf.second);
	delete keyReg;


	unsigned int exceededSpace=centerNode->getUsedSize()-(centerNode->getSize()-16);
	unsigned int registersSize=0;
	unsigned int i=0;
	Registers::iterator it = (centerNode->regs).begin();

	while(registersSize<exceededSpace){
		registersSize+=(*it)->getSize();
		i++;
		it++;
	}


	if((registersSize+leftNode->getUsedSize())<(leftNode->getSize()-16)){

		//Si entran en nodo izquierdo los copio y actualizo registro en root
		it = (centerNode->regs).begin();
		registersSize=0;

		while(registersSize<exceededSpace){
			registersSize+=(*it)->getSize();
			leftNode->insert(*(*it),root,manager);
			(centerNode->registerCount)--;
			delete(*it);
			it++;
		}
		(centerNode->regs).erase((centerNode->regs).begin(),it);
		/*std::queue<unsigned int> offsetss;
		centerNode->toOstream(std::cout,offsetss);*/
		it = (centerNode->regs).begin();
		registersSize=0;
		unsigned int freeSpace2=leftNode->getSize()-leftNode->getUsedSize()-16;
		bool finish=false;
		while(!finish){
			registersSize+=(*it)->getSize();
			if(registersSize<(freeSpace2/2)){
				leftNode->insert(*(*it),root,manager);
				(centerNode->registerCount)--;
				delete(*it);
				it++;
			}
			else
				finish=true;
		}
		(centerNode->regs).erase((centerNode->regs).begin(),it);
		/*std::queue<unsigned int> offsetss;
		centerNode->toOstream(std::cout,offsetss);*/

		root->remove(keyRegister);
		Register* firstReg=(dynamic_cast<LeafRegister*>(*((centerNode->regs).begin())))->getKeyRegister();
		LevelRegister firstRegister=LevelRegister(*firstReg,lf.second);
		delete firstReg;
		root->insert(firstRegister);
		centerNode->fmodified = true;
		manager.writeNode(*leftNode);
	}
	else{

		//Muevo ultimos registros de nodo anterior al nuevo
		it = (leftNode->regs).begin();
		registersSize=0;
		while(registersSize<leftNode->getSize()*0.66){
			registersSize+=(*it)->getSize();
			it++;
		}
		Registers::iterator it2 = it;		
		while(it!=(leftNode->regs).end()){
			((Node*)centerNode)->insert(*(*it));
			(leftNode->registerCount)--;
			delete (*it);
			it++;
		}
		(leftNode->regs).erase(it2,(leftNode->regs).end());
		//Creo otro nodo que va a ser el de mas a la izq
		centerNode->newNode = new LeafNode(this->level,NodeManager::NO_OFFSET,this->size);
		LeafNode* centerNewNode=dynamic_cast<LeafNode*>(centerNode->newNode);
		//Muevo los ultimos registro de este nodo hasta que tenga 0.66 del tamaño maximo
		it = (centerNode->regs).begin();
		registersSize=0;
		while(registersSize<leftNode->getSize()*0.66){
			registersSize+=(*it)->getSize();
			it++;
		}
		it2 = it;	
		while(it!=(centerNode->regs).end()){
			(centerNode->newNode)->insert(*(*it));
			(centerNode->registerCount)--;
			delete (*it);
			it++;
		}
		(centerNode->regs).erase(it2,(centerNode->regs).end());

		//Guardo registro clave de nuevo nodo en overflowRegister
		Register* lR = dynamic_cast<LeafRegister*>(*((centerNewNode->regs).begin()))->getKeyRegister();
		overflowRegister = new LevelRegister(*lR,NodeManager::NO_OFFSET);
		delete lR;

		//Guardo cambios en nodo izquierdo
		root->remove(keyRegister);

		Register* firstReg=(dynamic_cast<LeafRegister*>(*((centerNode->regs).begin())))->getKeyRegister();
		LevelRegister firstRegister=LevelRegister(*firstReg,lf.second);
		delete firstReg;

		root->insert(firstRegister);
		centerNode->foverflow = true;
		manager.writeNode(*leftNode);
	}

	

	return ret;
}

bool LeafNode::reacomodateRegistersToRight(LevelNode* root, LeafNode* leftNode,LeafNode* rightNode, NodeManager& manager){
	bool ret =false;
	
	Register* keyReg=(dynamic_cast<LeafRegister*>(*((rightNode->regs).begin())))->getKeyRegister();
	LevelRegister keyRegister(*keyReg,NodeManager::NO_OFFSET);
	std::pair<bool,unsigned int> lf = root->getSubTree(*keyReg);
	keyRegister.setRightChild(lf.second);
	delete keyReg;


	unsigned int exceededSpace=leftNode->getUsedSize()-(leftNode->getSize()-16);
	unsigned int registersSize=0;
	unsigned int i=0;
	Registers::iterator it = (leftNode->regs).end();
	while(registersSize<exceededSpace){
		it--;
		registersSize+=(*it)->getSize();
		i++;
	}
	if((registersSize+rightNode->getUsedSize())<(rightNode->getSize()-16)){
		//Si entran en nodo izquierdo los copio y actualizo registro en root
		it = (leftNode->regs).end();
		registersSize=0;

		while(registersSize<exceededSpace){
			it--;
			registersSize+=(*it)->getSize();
			rightNode->insert(*(*it),root,manager);
			delete(*it);
			(leftNode->registerCount)--;
		}
		(leftNode->regs).erase(it,(leftNode->regs).end());

		//Copio demas registros para que ambos esten por la mitad

		it = (leftNode->regs).end();
		registersSize=0;
		unsigned int freeSpace2=rightNode->getSize()-rightNode->getUsedSize()-16;
		bool finish=false;
		while(!finish){
			it--;
			registersSize+=(*it)->getSize();
			if(registersSize<(freeSpace2/2)){
				
				rightNode->insert(*(*it),root,manager);
				delete(*it);
				(leftNode->registerCount)--;
			}
			else{
				finish=true;
				it++;
			}
		}
		(leftNode->regs).erase(it,(leftNode->regs).end());


		root->remove(keyRegister);

		Register* firstReg=(dynamic_cast<LeafRegister*>(*((rightNode->regs).begin())))->getKeyRegister();
		LevelRegister firstRegister=LevelRegister(*firstReg,lf.second);
		delete firstReg;

		root->insert(firstRegister);
		leftNode->fmodified = true;
		manager.writeNode(*rightNode);
	}
	else{
		//Muevo ultimos registros de nodo anterior al nuevo
		it = (leftNode->regs).begin();
		registersSize=0;
		while(registersSize<leftNode->getSize()*0.66){
			registersSize+=(*it)->getSize();
			it++;
		}
		it--;
		Registers::iterator it2 = it;
		leftNode->newNode = new LeafNode(this->level,NodeManager::NO_OFFSET,this->size);
		LeafNode* leftNewNode=dynamic_cast<LeafNode*>(leftNode->newNode);

		while(it!=(leftNode->regs).end()){
			(leftNode->newNode)->insert(*(*it));
			delete (*it);
			(leftNode->registerCount)--;
			it++;
		}
		(leftNode->regs).erase(it2,(leftNode->regs).end());

		//Muevo los primeros registros de nodo izquierdo hasta que tenga 0.66 del tamaño maximo
		it = (rightNode->regs).end();
		registersSize=0;
		while(registersSize<rightNode->getSize()*0.66){
			it--;
			registersSize+=(*it)->getSize();
		}
		it2 = it;	
		while(it!=(rightNode->regs).begin()){
			it--;
			(leftNode->newNode)->insert(*(*it));
			delete (*it);
			(rightNode->registerCount)--;
		}
		(rightNode->regs).erase((rightNode->regs).begin(),it2);

		//Guardo registro clave de nuevo nodo en overflowRegister
		Register* lR = dynamic_cast<LeafRegister*>(*((leftNewNode->regs).begin()))->getKeyRegister();
		overflowRegister = new LevelRegister(*lR,NodeManager::NO_OFFSET);
		delete lR;
		//Guardo cambios en nodo derecho
		root->remove(keyRegister);
		Register* firstReg=(dynamic_cast<LeafRegister*>(*((rightNode->regs).begin())))->getKeyRegister();
		LevelRegister firstRegister=LevelRegister(*firstReg,lf.second);
		delete firstReg;
		root->insert(firstRegister);
		leftNode->foverflow = true;
		manager.writeNode(*rightNode);
	}
	return ret;
}

bool LeafNode::remove(NodeRegister& reg){
	bool ret = Node::remove(reg);
	if(this->getUsedSize()<(this->getSize()-16)/2/*Cantidad de regMax Hoja TODO*/)
		this->funderflow = true;
	else 
		this->fmodified = true;	
	return ret;
}

char* LeafNode::toBytes(char* data,const RegisterFactory& factory)const {
	char* temp = Node::toBytes(data,factory);
	memcpy(temp,&previousNode,sizeof(unsigned int));
	temp += sizeof(unsigned int);
	memcpy(temp,&nextNode,sizeof(unsigned int));
	temp += sizeof(unsigned int);
	for(Registers::iterator it=regs.begin();it!=regs.end();++it){
		temp = (*(it))->toBytes(temp,factory);
	}	
	return temp;
}
		
char* LeafNode::toNode(char* data,const RegisterFactory& factory){
	char* temp = Node::toNode(data,factory);
	memcpy((void*)&previousNode,temp,sizeof(unsigned int));
	temp+=sizeof(unsigned int);
	memcpy((void*)&nextNode,temp,sizeof(unsigned int));
	temp+=sizeof(unsigned int);
	for(unsigned int c=0;c<registerCount;c++){
		LeafRegister* reg = new LeafRegister();
		temp = reg->toRegister(temp,factory);
		regs.insert(reg);
	}
	return temp;
}

std::ostream& LeafNode::toOstream(std::ostream& out,std::queue<unsigned int>& offsets)const{
	out << "/** Imprimiendo Nodo Hoja **/" << std::endl;
	out << "\t -- Informacion de cabecera ---" << std::endl;
	out << "\t Offset del Nodo : " << this->offset << std::endl;
	out << "\t Cantidad de Registros : " << registerCount << std::endl;
	out << "\t Nivel : " << level << std::endl;
	out << "\t Siguiente : "<<nextNode<<std::endl;
	out << "\t Anterior : "<<previousNode<<std::endl;
	out << "\t -- Informacion de los registros ---" << std::endl;
	for(Registers::iterator it=regs.begin();it!=regs.end();++it){		
		(*it)->toOstream(out);
	}	
	out << "/** Fin Nodo Hoja **/" << std::endl;
	return out;
}

NodeRegister* LeafNode::joinNodes(Node* nodo){
	NodeRegister* nodoIntermedio = Node::joinNodes(nodo);
	LeafNode* leaf = dynamic_cast<LeafNode*>(nodo);
/*	if(leaf->getFirstRegister()<this->getFirstRegister()){
		this->setPreviousNode(leaf->getPreviousNode());
		nodoIntermedio = this->getFirstRegister();
	}
	else{*/
	this->setNextNode(leaf->getNextNode());
	/*}*/
	NodeRegister* re = NULL;
	if(nodoIntermedio!=NULL){
		Register* kr = (dynamic_cast<LeafRegister*>(nodoIntermedio))->getKeyRegister();
		re = new LevelRegister(*kr, NodeManager::NO_OFFSET);
		delete kr;
	}
	delete nodoIntermedio;
	return re;
}

NodeRegister* LeafNode::extractFirstRegister(){ 
	NodeRegister* NR = Node::extractFirstRegister();
	if(this->getUsedSize()<(this->getSize()-16)/2/*Cantidad de regMax Nivel TODO*/)
		this->funderflow = true;
	else 
		this->fmodified = true;	
	return NR;
}

NodeRegister* LeafNode::extractLastRegister(){ 
	NodeRegister* NR = Node::extractLastRegister();
	if(this->getUsedSize()<(this->getSize()-16)/2/*Cantidad de regMax Nivel TODO*/)
		this->funderflow = true;
	else 
		this->fmodified = true;	
	return NR;
}
/*
bool LeafNode::modify(NodeRegister& nodeRegister){
	bool ret = false;
	LeafRegister* leafRegister = dynamic_cast<LeafRegister*>(&nodeRegister);
	Registers::iterator it = regs.find(leafRegister);
	if(it!=regs.end()){
		((*it)->getRegister()).setFields(leafRegister->getRegister());
		ret = true;
	}
	return ret;
}*/

unsigned int LeafNode::getUsedSize(){
	Registers::iterator it = regs.begin();
	unsigned int size=0;
	while(it!=regs.end()){
		size+=(*it)->getSize();
		it++;
	}
	return size;
}

bool LeafNode::search(NodeRegister& reg){
	Registers::iterator it = regs.end();
	bool finish=false;
	bool ret = true;
	while((it!=regs.begin())&&(!finish)){
		it--;
		if((*(*it))<reg){
			reg.getRegister().setFields((*it)->getRegister());
			finish=true;
		}
		else{
			if(!(reg<(*(*it)))){
				reg.getRegister().setFields((*it)->getRegister());
				finish=true;
			}
		}
	}

	if(finish==false){
		if(regs.size()>0){
			(*it)->getRegister();
			reg.getRegister().setFields((*it)->getRegister());
		}
		else 
			ret=false;
	}
	
	return ret;
}

bool LeafNode::replace(const NodeRegister& newReg,const NodeRegister& oldReg,LevelNode* root, NodeManager& manager){
	NodeRegister* nrAux=oldReg.duplicate();
	if(!Node::remove(*nrAux))return false;	
	delete nrAux;
	return this->insert(newReg ,root, manager);
}



